<?php 
namespace addons\payment\library\impl;

use addons\payment\library\BaseService;
use app\admin\model\payment\Order;
use Yansongda\Pay\Pay;
use addons\payment\library\exception\ConfigErrorException;
use addons\payment\library\exception\PaymentException;
use app\admin\model\payment\Channel;
use Symfony\Component\HttpFoundation\Response;
use think\Log;
use Exception;

class Wechat extends BaseService {

    public function getPay(Channel $channel) {
        $config = $channel->config;
        if (!isset($config['mch_id']) || !isset($config['key'])) {
            throw new ConfigErrorException("配置不完全!");
        }
        return Pay::wechat([
            'appid' => $config['appid'] ?? '', // APP APPID
            'app_id' => $config['app_id'] ?? '', // 公众号 APPID
            'miniapp_id' => $config['miniapp_id'] ?? '', // 小程序 APPID
            'mch_id' => $config['mch_id'],
            'key' => $config['key'],
            'notify_url' =>  request()->domain() . '/addons/payment/payback/notify/channel_id/' . $channel->id,
            'cert_client' => ROOT_PATH . ($config['cert_file'] ?? ''), // optional, 退款，红包等情况时需要用到
            'cert_key' => ROOT_PATH . ($config['key_file'] ?? ''),// optional, 退款，红包等情况时需要用到
            'log' => [ // optional
                'file' =>  LOG_PATH . DS . 'alipay ' . DS . 'wechat.log',
                'level' => config('app.debug') ? 'debug' : 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                'type' => config('app.debug') ? 'single' : 'daily', // optional, 可选 daily.
                'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
            ],
            'http' => [ // optional
                'timeout' => 5.0,
                'connect_timeout' => 5.0,
                'verify' => false 
                // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
            ],
            // 'mode' => 'dev',
        ]);
    }

    /**
     * 判断是否能支付
     *
     * @param Order $order
     * @return boolean
     */
    public function canpay(Order $order)
    {
        $config = $order->channel->config;
        if (!isset($config['mch_id']) || !isset($config['key'])) {
            $this->errMsg = "配置不完整";
            return false;
        }
        return true;
    }

    /**
     * 电脑支付
     *
     * @param Order $order
     * @param array $params
     * @return Response
     */
    public function payWeb(Order $order, $params = []) {
        return false;
        // return $this->pay($order, $params);
    }

    /**
     * 手机网站支付
     *
     * @param Order $order
     * @param array $params
     * @return Response
     */
    public function payWap(Order $order, $params = []) {
        return $this->pay($order, $params);
    }

    /**
     * app支付
     *
     * @param Order $order
     * @param array $params
     * @return string app支付字符串
     */
    public function payApp(Order $order, $params = []) {
        $res = $this->pay($order, $params);
        return $res->getContent();
    }

    /**
     * 扫码
     *
     * @param Order $order
     * @param array $params
     * @return string 二维码内容
     */
    public function payScan(Order $order, $params = []) {
        $pay = $this->getPay($order->channel);
        $params = array_merge([
            'out_trade_no' => $order->order_number,
            'total_amount' => $order->price,
            'subject' => $order->title,
        ], $params);
        $res = $pay->scan($params);
        return $res->qr_code;
    }

    /**
     * 转账
     *
     * @param Order $order
     * @param array $params
     * @return Collection
     */
    public function payTransfer(Order $order, $params = []) {
        $pay = $this->getPay($order->channel);
        $params = array_merge([
            'out_biz_no' => $order->order_number,
            'trans_amount' => $order->price,
            'product_code' => 'TRANS_ACCOUNT_NO_PWD',
            'payee_info' => [
                'identity' => '',
                'identity_type' => 'ALIPAY_LOGON_ID'
            ]
        ], $params);
        return $pay->transfer($params);
    }

    /**
     * 小程序
     *
     * @param Order $order
     * @param array $params
     * @return Collection
     */
    public function payMini(Order $order, $params = []) {
        if (!isset($params['buyer_id'])) {
            throw new PaymentException("缺失参数:buyer_id");
        }
        return $this->pay($order, $params);
    }

    /**
     * 获取支付参数
     * @param Order $order 订单实例
     * @param array $params 额外参数
     * @return array|Response|Collection
     */
    public function pay(Order $order, $params = []) {
        $pay = $this->getPay($order->channel);
        $params = array_merge([
            'out_trade_no' => $order->order_number,
            'total_amount' => $order->price,
            'subject' => $order->title,
        ], $params);
        return $pay->{$order->pay_type}($params)->send();
    }

    /**
     * 回调处理
     *
     * @param array $data
     * @param Channel $channel 渠道
     * @return boolean|array|string|object  boolean=转换成整型 array=json string=return object=reutrn
     */
    public function back($data, Channel $channel) {
        $pay = $this->getPay($channel);
        try{
            $res = $pay->verify();
            $order = Order::get(['order_number' => $res['out_trade_no']]);
            if (!$order) {
                return $pay->success()->send();
            }
            if ($order->status != 'wait') {
                return $pay->success()->send();
            }
            $order->pay('pay', $res['total_amount'], [
                'back_data' => json_encode($res->toArray())
            ]);
            return $pay->success()->send();
        } catch (Exception $e) {
            Log::error($e->getMessage());
            $this->errMsg = $e->getMessage();
            return false;
        }
        return true;
    }
}